iT邦幫忙

2026 iThome 鐵人賽

0

一、今日目標

延續 Day 25 完成的醫師查詢與每週門診時間表串接,今天開始開發智慧醫院管理平台的會員登入與註冊功能。

在前面的開發過程中,我已經使用 Figma 設計登入與註冊頁面,並將 HTML、CSS 轉換為 Angular Component。

目前登入與註冊頁已經有基本的表單欄位、按鈕與 RWD 排版,但原本只有畫面,尚未真正連接後端資料庫。

例如使用者點擊登入按鈕時,原本只會顯示「尚未提供帳號驗證」,而註冊頁也沒有真正建立會員帳號。

因此,今天希望將原本的 Demo 登入與註冊頁,改成能透過 ASP.NET Core Web API 操作 Oracle Database 的會員系統。

今日主要目標

  1. 確認原有 Angular 登入與註冊頁的實作方式。
  2. 建立 Oracle USERS 與 PATIENTS 資料表。
  3. 實作 ASP.NET Core 會員註冊 API。
  4. 使用 PasswordHasher 安全儲存密碼。
  5. 實作登入、查詢目前會員及登出 API。
  6. 使用 Cookie Authentication 管理登入狀態。
  7. 加入 CSRF 防護與登入限流。
  8. 建立 Angular AuthService。
  9. 將 Reactive Forms 與正式 API 串接。
  10. 整合 Header、Route Guard 與個人資料頁。
  11. 測試註冊、登入、重新整理與錯誤處理。

這次主要以完成前後端登入驗證為目標,保留之前已完成的登入、註冊 HTML、CSS 與 RWD,不重新設計畫面。


二、確認現有登入與註冊功能

正式實作 API 之前,我先檢查 Angular 專案中的登入與註冊相關程式。

目前兩個頁面共用 AuthPage Component,透過 Angular Router 區分不同模式:

/login
   ↓
AuthPage:登入模式

/register
   ↓
AuthPage:註冊模式

這次沿用 Standalone Components、Reactive Forms、signals 與 OnPush 的設計。

1. 原本的登入頁

目前登入頁包含:

  • 帳號。
  • 密碼。
  • 記住我。
  • 登入按鈕。
  • 前往註冊頁的連結。

原本登入頁主要負責呈現畫面,沒有真正向 ASP.NET Core 發送登入請求。

2. 原本的註冊頁

註冊頁原本包含:

欄位 原本用途
姓名 輸入使用者姓名
身分證字號 個人身分資料
出生日期 個人基本資料
手機 聯絡方式
帳號 登入使用的帳號
密碼 設定登入密碼
確認密碼 再次輸入密碼
同意條款 確認使用者同意

這次檢查時發現,雖然部分欄位已經顯示輸入格式提示,但實際上還沒有完整的表單驗證。

例如帳號提示需要 6–20 位英數字元,但提示文字本身並不會阻止錯誤資料送出。

因此,後續需要加入 Angular Reactive Forms 驗證。

3. 原本的 SessionService

除了登入頁,專案原本還有 SessionService,主要用來支援 Demo 會員及展示功能。

但這套機制並不是正式的後端驗證。

因此,這次沒有直接沿用原本的 Demo 密碼判斷方式,而是另外建立正式 AuthService。

另外,原本的「我的預約」與預約詳細頁仍使用 Demo 資料,因此這次也需要避免正式登入的會員看到展示資料後,誤以為那是自己的預約紀錄。


三、建立 Oracle USERS 與 PATIENTS 資料表

完成現有功能分析後,接著開始建立會員相關資料表。

原本 Day 22 已經規劃過部分 Oracle 資料庫結構,因此這次先檢查既有 SQL 草稿,再建立獨立的 Day 26 建表腳本。

這次沒有重新設計整個資料庫,而是先建立登入與註冊需要的兩張資料表:

  • USERS:保存會員登入帳號。
  • PATIENTS:保存與會員對應的病人基本資料。

1. USERS 資料表

USERS 主要負責保存帳號、密碼雜湊與帳號狀態。

欄位 Oracle 型別 用途
USER_ID NUMBER(12,0) 會員 ID
USERNAME VARCHAR2(20 CHAR) 登入帳號
EMAIL VARCHAR2(254 CHAR) Email,目前不使用
PHONE VARCHAR2(30 CHAR) 聯絡手機
PASSWORD_HASH VARCHAR2(512 BYTE) 密碼雜湊
CREATED_AT TIMESTAMP WITH TIME ZONE 建立時間
ACCOUNT_STATUS VARCHAR2(20 CHAR) 帳號狀態

其中,最重要的欄位是 PASSWORD_HASH。

這次不在資料庫保存明文密碼,而是由 ASP.NET Core 將密碼轉換成安全的雜湊結果,再存入 Oracle。

另外,USERNAME 設定 UNIQUE,避免使用者註冊重複帳號。

2. PATIENTS 資料表

PATIENTS 則保存與會員對應的病人資料。

欄位 Oracle 型別 用途
PATIENT_ID NUMBER(12,0) 病人 ID
USER_ID NUMBER(12,0) 對應 USERS
PATIENT_NAME VARCHAR2(100 CHAR) 病人姓名

這次使用外鍵建立關聯:

USERS
  │
  └── USER_ID
         │
         ▼
      PATIENTS
         │
         └── PATIENT_ID

PATIENTS.USER_ID 同時具有 FOREIGN KEY 與 UNIQUE 限制,讓一個會員最多對應一筆病人資料。

不過,FOREIGN KEY 與 UNIQUE 並不能保證每個會員一定有病人資料,因此後續註冊 API 還需要使用 Transaction 確保兩張表一起建立成功。

3. 使用 Oracle Identity 自動產生 ID

之前醫師資料使用手動指定的測試 ID,但正式會員註冊不能讓前端自行決定使用者 ID。

因此這次使用:

user_id NUMBER(12,0)
GENERATED ALWAYS AS IDENTITY

GENERATED ALWAYS AS IDENTITY 表示主鍵由 Oracle 自動產生。

這樣就不需要在註冊 API 中自行計算下一個 ID,也能避免使用 MAX(id)+1 時發生多人同時註冊的衝突問題。

PATIENTS.PATIENT_ID 也使用相同方式。

4. 遇到 ORA-01031 權限不足

第一次在 SQL Developer 建立 USERS 時,遇到:

ORA-01031: insufficient privileges

一開始我以為是 CREATE TABLE 語法有問題,但檢查 Oracle 權限後發現,目前的 SMARTCARE_DEV 雖然有 CREATE TABLE,卻沒有 CREATE SEQUENCE。

這次與之前建立醫師排班表不同,因為新的資料表使用 Identity 自動產生 ID。

後來確認權限問題並補足必要權限後,重新執行 SQL,才成功建立兩張資料表。

5. SQL Developer 實際建立結果

這次在 SQL Developer 使用 SMARTCARE_DEV,成功建立:

Table USERS created.
Table PATIENTS created.

接著檢查 Identity:

TABLE_NAME COLUMN_NAME GENERATION_TYPE
USERS USER_ID ALWAYS
PATIENTS PATIENT_ID ALWAYS

另外,資料表的 PK、FK、UNIQUE 與 CHECK 限制都顯示:

ENABLED
VALIDATED

建表完成後,兩張資料表一開始都是 0 筆。

這次也學到,Oracle 的 CREATE TABLE 屬於 DDL,成功執行後會隱含 COMMIT,不需要另外手動提交建表操作。

USERS、PATIENTS 資料表

https://ithelp.ithome.com.tw/upload/images/20261031/20178845yaYfJUDvJ0.png


四、實作 ASP.NET Core 會員註冊 API

完成 Oracle 資料表後,開始建立 ASP.NET Core 註冊 API。

這次新增的主要檔案包括:

backend/SmartCare.Api/
├── Controllers/
│   └── AuthController.cs
├── Dtos/
│   └── AuthDtos.cs
├── Auth/
│   ├── AuthModels.cs
│   ├── AuthValidation.cs
│   ├── AuthService.cs
│   └── AuthSecurity.cs
└── Data/
    ├── UserRepository.cs
    └── RegistrationTransaction.cs

這次沒有將帳號相關查詢放進原本的 DoctorRepository,而是另外建立 UserRepository,讓醫師資料與會員資料分開管理。

1. 註冊 API

新增:

POST /api/auth/register

註冊時,Angular 會提供:

{
  "username": "smartcare01",
  "password": "ExamplePassword123!",
  "confirmPassword": "ExamplePassword123!",
  "displayName": "虛構測試會員",
  "phone": null,
  "acceptTerms": true
}

以上是 API 格式示意,不是實際測試帳號或密碼。

這次註冊 API 主要檢查:

  • 帳號格式是否正確。
  • 密碼長度是否符合要求。
  • 確認密碼是否一致。
  • 姓名是否填寫。
  • 手機格式是否正確。
  • 是否已同意條款。
  • 帳號是否已被使用。

通過驗證後,才開始新增資料。

2. 使用 PasswordHasher 儲存密碼

這次使用 ASP.NET Core 的 PasswordHasher 處理密碼。

核心概念是:

var hashedPassword = passwordHasher.HashPassword(
    user,
    password
);

以上是主要操作方式示意。

HashPassword() 會產生包含必要雜湊資訊的結果,再將結果保存於 Oracle 的 PASSWORD_HASH。

登入時則使用:

var result = passwordHasher.VerifyHashedPassword(
    user,
    storedPasswordHash,
    password
);

這樣後端不需要,也不應該透過讀取明文密碼來比較登入資料。

3. 使用 Oracle Transaction 確保資料一致

這次最重要的新觀念是 Transaction(交易)。

會員註冊時,需要同時建立:

  1. USERS 帳號。
  2. PATIENTS 病人資料。

如果第一筆成功、第二筆失敗,卻沒有回復交易,就會留下只有會員帳號、沒有病人資料的不完整紀錄。

因此這次採用:

收到註冊資料
       ↓
驗證欄位
       ↓
PasswordHasher
       ↓
開始 Oracle Transaction
       ↓
INSERT USERS
       ↓
取得 USER_ID
       ↓
INSERT PATIENTS
       ↓
兩筆都成功?
   ┌───┴───┐
   │       │
  是       否
   │       │
 COMMIT  ROLLBACK

新增 USERS 後,利用 Oracle RETURNING 取得 Identity 產生的 USER_ID,再將這個 ID 寫入 PATIENTS。

兩筆新增操作使用相同的 OracleConnection 與 OracleTransaction,成功才提交,失敗就回復。

4. 實際驗證 Rollback

為了確認交易真的有效,這次也執行了一個預期失敗的測試。

測試中故意讓第二筆 PATIENTS 寫入觸發:

ORA-01400

代表必要欄位不能為 NULL。

結果確認交易 Rollback 後:

  • 沒有留下失敗測試的 USERS。
  • 沒有留下對應的 PATIENTS。
  • 沒有產生孤立的病人紀錄。

這次讓我理解到,Transaction 不只是資料庫語法,也是在保護使用者資料的一致性。


五、實作登入與身分驗證

完成註冊後,下一步是讓使用者能夠登入,並在後續頁面保持登入狀態。

這次新增:

POST /api/auth/login
GET /api/auth/me
POST /api/auth/logout

1. 登入 API

登入時由 Angular 傳送:

{
  "username": "smartcare01",
  "password": "ExamplePassword123!",
  "rememberMe": false
}

後端會依序:

  1. 正規化 username。
  2. 從 Oracle 查詢使用者。
  3. 檢查帳號是否啟用。
  4. 使用 PasswordHasher 驗證密碼。
  5. 驗證成功後建立登入身分。

如果帳號不存在或密碼錯誤,都使用相同的登入失敗訊息,避免直接透露帳號是否存在。

2. 為什麼選擇 Cookie Authentication?

這次評估後,選擇 ASP.NET Core Cookie Authentication 作為目前 Angular 網站的登入機制。

主要原因是這個專案目前以單一網站為主,Angular 與 API 使用相對 /api 路徑,適合由瀏覽器管理驗證 Cookie。

登入成功後,後端透過 Set-Cookie 建立登入狀態。

Angular 不需要將驗證憑證放進 localStorage 或 sessionStorage。

這次 Cookie 的主要設定包括:

設定 用途
HttpOnly 降低 JavaScript 直接讀取驗證 Cookie 的風險
SameSite=Lax 限制部分跨站請求攜帶 Cookie
有效期限 20 分鐘 控制登入狀態的存續時間
不滑動延長 不因每次請求而自動延長期限
Secure 非 Development 環境要求安全傳輸

目前「記住我」尚未啟用永久登入。

3. GET /api/auth/me

新增:

GET /api/auth/me

這支 API 用來查詢目前已登入的會員。

例如成功回應:

{
  "data": {
    "id": 1,
    "username": "smartcare01",
    "displayName": "虛構測試會員",
    "patientId": 1
  }
}

回傳資料不包含密碼及密碼雜湊。

這支 API 的用途是讓 Angular 在重新整理頁面後,重新確認目前使用者是否仍有有效的登入狀態。

4. 登出 API

新增:

POST /api/auth/logout

使用者登出時,後端清除目前瀏覽器的驗證 Cookie。

正常情況下,登出後再次呼叫 /api/auth/me,應該得到 HTTP 401。

不過目前的登出機制只處理這個瀏覽器的 Cookie,尚未實作其他裝置或已複製票證的即時撤銷。


六、CSRF 防護與登入安全

完成 Cookie Authentication 後,接著要處理另一個重要的問題:CSRF。

1. CSRF 是什麼?

CSRF(Cross-Site Request Forgery,跨站請求偽造)是一種利用瀏覽器自動攜帶驗證資訊的特性,誘使使用者在已登入的狀態下發送非預期請求的攻擊方式。

由於這次使用 Cookie Authentication,因此不能只完成登入 Cookie,還需要搭配 CSRF 防護。

2. 建立 CSRF API

後端新增:

GET /api/auth/csrf

這次的流程是:

Angular 準備送出註冊/登入
          ↓
GET /api/auth/csrf
          ↓
後端提供 CSRF Token
          ↓
Angular 發送 POST
          ↓
X-XSRF-TOKEN Header
          ↓
ASP.NET Core 驗證 Token
          ↓
執行註冊/登入/登出

Angular 的 HttpClient 具備 XSRF 支援,後端則使用 ASP.NET Core IAntiforgery 驗證。

這次主要使用:

  • XSRF-TOKEN:供 Angular 使用的 CSRF Cookie。
  • X-XSRF-TOKEN:POST 請求所附加的 Header。

這兩者是 CSRF 防護的一部分,與 HttpOnly 的登入驗證 Cookie 不同。

3. 加入登入限流

為了避免短時間大量嘗試登入與註冊,這次後端也加入 Rate Limiting。

目前設定:

API 限制
登入 每個來源 IP 每分鐘 5 次
註冊 每個來源 IP 每 10 分鐘 3 次

超過限制時,回傳:

HTTP 429 Too Many Requests

並提供 Retry-After 資訊。

這次的限流主要適合目前單一開發程序使用,正式部署若有多台伺服器,還需要進一步規劃。


七、建立 Angular AuthService

後端 API 完成後,開始進行 Angular 前端串接。

這次沒有把 HTTP 請求直接寫在登入頁中,而是另外建立 AuthService,集中管理註冊、登入、查詢目前會員及登出。

主要新增:

src/app/core/
├── auth-api.models.ts
├── auth.service.ts
└── auth-validation.ts

1. 使用 TypeScript Interface 定義 API 資料

註冊 Request 與登入 Request 分開定義,避免直接把整個 Reactive Forms 內容傳到後端。

例如會員回傳資料:

export interface AuthUser {
  id: number;
  username: string;
  displayName: string | null;
  patientId: number | null;
}

這樣前端可以使用明確的欄位名稱與型別。

2. 集中管理 Auth API

AuthService 使用既有的 HttpClient,透過相對路徑:

/api/auth

呼叫後端。

主要方法包括:

register()
login()
getCurrentUser()
logout()

另外也包含取得 CSRF Token 與處理登入狀態的功能。

這樣登入頁、Header 與 Route Guard 不需要各自重新撰寫 HTTP 請求。

3. 使用 AuthState 管理登入狀態

這次比較重要的設計,是將登入狀態分成四種:

export type AuthState =
  | { status: 'checking' }
  | { status: 'authenticated'; user: AuthUser }
  | { status: 'anonymous' }
  | { status: 'error' };

這四種狀態分別代表:

狀態 意義
checking 正在確認登入狀態
authenticated 已登入
anonymous 尚未登入
error 無法完成身分查詢

例如 Angular 啟動時呼叫 /api/auth/me:

  • HTTP 200:將狀態設為 authenticated。
  • HTTP 401:設為 anonymous。
  • HTTP 503 或網路錯誤:保留 error 狀態。

這樣可以避免 API 暫時無法使用時,前端直接把使用者當成正常登出。


八、串接登入與註冊 Reactive Forms

完成 AuthService 後,接著修改原本登入與註冊頁的表單功能。

這次主要調整 auth.ts 與 auth.html,沒有重新修改原本的 CSS 排版。

1. 登入表單

原本登入頁已有帳號與密碼欄位。

這次主要新增:

  • 帳號必填。
  • 密碼必填。
  • 登入時呼叫後端 API。
  • 顯示登入中的狀態。
  • 防止重複送出。
  • 登入失敗時顯示對應錯誤。
  • 登入後清除密碼欄位。

另外,原本帳號欄的 placeholder 誤寫為「請輸入姓名」,也在這次調整成符合實際用途的提示。

2. 註冊表單

註冊頁加入 Reactive Forms 驗證。

目前主要規則:

欄位 驗證方式
姓名 必填,最多 100 字元
帳號 6–20 位英數字元
密碼 15–128 個 Unicode code point
確認密碼 必須與密碼相同
手機 選填,有值時需符合台灣手機格式
同意條款 必須勾選
身分證、生日 暫不蒐集

這次特別注意密碼長度的計算方式。

JavaScript 字串的 length 計算的是 UTF-16 code units,而後端這次採用 Unicode code point 的長度規則。

如果前後端使用不同的計算方式,就可能產生「前端允許、後端拒絕」的情況。

因此這次另外建立共用驗證工具,讓 Angular 與後端使用一致的長度規則。

3. 不直接傳送整個 FormGroup

原本註冊畫面包含身分證與生日,但這次的後端資料表尚未規劃保存這兩項資料。

因此,目前先將欄位停用,不蒐集或傳送。

正式發送註冊請求時,只建立後端需要的欄位:

const request = {
  username,
  password,
  confirmPassword,
  displayName,
  phone,
  acceptTerms,
};

這樣可以避免不必要的資料被送到 API。

4. 註冊成功與登入流程

目前設計為:

填寫註冊資料
      ↓
Angular 表單驗證
      ↓
GET /api/auth/csrf
      ↓
POST /api/auth/register
      ↓
Oracle 建立會員
      ↓
顯示註冊結果
      ↓
前往登入頁
      ↓
POST /api/auth/login
      ↓
建立 Cookie
      ↓
進入會員頁

這次註冊成功後不會自動登入,使用者仍需要使用剛建立的帳號與密碼登入。

Angular 註冊頁與表單驗證

https://ithelp.ithome.com.tw/upload/images/20261031/20178845Rvj8crUYvW.png


九、Header、Route Guard 與會員資料整合

完成登入與註冊後,接著需要讓網站其他頁面知道目前的登入狀態。

1. Header 登入狀態

原本 Header 使用 Demo SessionService 判斷使用者是否登入。

這次改為使用正式 AuthService 的登入狀態。

例如:

AuthState Header 顯示
checking 正在確認登入狀態
anonymous 登入入口
authenticated 會員名稱或會員操作
error 身分查詢錯誤或重試入口

這樣 Angular 不需要依賴 sessionStorage 中的 Demo 身分判斷正式會員。

2. Route Guard

這次也調整 Auth Guard,讓需要登入的頁面先確認目前會員狀態。

例如使用者尚未登入就進入:

/profile

系統會導向登入頁。

登入成功後,再依照安全的 returnUrl 返回站內頁面。

這次也限制 returnUrl 只能使用允許的站內路徑,避免登入後被導向不受信任的外部網站。

3. 將正式會員與 Demo 資料分開

這次還遇到一個重要問題:

原本的個人資料頁與預約頁,顯示的不是正式會員資料,而是固定 Demo 內容。

如果直接把這些頁面接到新的登入功能,可能會造成使用者誤以為展示資料就是自己的個人資料或預約紀錄。

因此這次調整為:

  • /profile:顯示正式登入會員的資料。
  • /demo/profile:保留原本展示用個人資料。
  • 預約相關 Demo 頁:加入展示資料說明。

目前登入功能雖然完成,但「我的預約」仍沒有串接正式預約 API。

登入成功畫面

https://ithelp.ithome.com.tw/upload/images/20261031/20178845fpBV6ozVBG.png


十、測試結果與問題排除

完成後端及前端功能後,這次分別使用 Mock、真實 Oracle HTTP、Angular 單元測試與瀏覽器進行驗證。

1. ASP.NET Core 後端測試

本次後端測試結果:

測試類型 實際結果
Mock 資料層與安全元件測試 304/304 通過
真實 Oracle 醫師 API 回歸 72/72 通過
Program 啟動與端點 27/27 通過
真實 Oracle Auth HTTP 測試 91/91 通過
Oracle Rollback 補驗 7/7 通過
後端 Build 0 警告、0 錯誤

這些數字是通過的斷言數,不代表相同數量的獨立業務案例。

其中,停用帳號、部分資料庫故障等情境主要由 Mock 測試驗證,沒有刻意中斷 Oracle。

2. Angular 前端測試

完成 Angular AuthService 與畫面串接後,執行完整測試。

項目 結果
Angular 單元測試 163/163 通過
測試檔案數 21
TypeScript 應用程式檢查 通過
TypeScript 測試檢查 通過
Production Build 成功,無警告/錯誤
登入/註冊可執行無障礙規則 通過,未涵蓋色彩對比

這次也確認,原本的醫師列表、搜尋、詳細頁與每週門診時間表沒有因新增 AuthService 而受到影響。

3. 真實瀏覽器註冊測試

完成 Angular 串接後,我在瀏覽器實際操作註冊頁。

一開始填寫資料並點擊「建立帳號」後,沒有看到明顯的成功訊息,也沒有在 Network 中找到 register 請求。

因此我先使用 SQL Developer 查詢 USERS,確認是否真的有新增帳號。

結果發現資料庫已經出現透過 Angular 註冊的新測試帳號:

syy000
syy001

這表示註冊請求確實曾成功建立會員資料。

不過,當時沒有取得對應的 Network HTTP 201 紀錄,因此不能只根據這次畫面操作宣稱已經親眼確認該次請求的狀態碼。

這也讓我學到:當畫面沒有明顯反應時,不能直接判斷 API 失敗,需要從瀏覽器及資料庫兩邊確認。

4. 真實瀏覽器登入測試

接著使用新註冊的測試帳號登入。

登入後,頁面顯示登入成功,進入 /profile 也能看到對應的會員資料。

另外,我在 /profile 重新整理頁面,確認登入狀態仍然保留。

這表示 Angular 已經可以透過後端的 Cookie 與會員身分查詢機制,在頁面重新整理後維持登入狀態。

但當時 Network 沒有保存到 login 請求的完整紀錄,因此這次主要以實際畫面與會員狀態作為瀏覽器驗證證據。

5. Network 篩選造成看不到請求

測試過程中,還遇到一個操作問題。

原本想查看登入及登出的 HTTP 狀態,但 Chrome DevTools 的 Network 沒有顯示請求。

後來才發現,篩選欄還保留之前測試醫師 API 時輸入的:

doctors

因此 Network 只顯示符合這個條件的請求,login、logout 與 me 都被篩選掉了。

清除篩選欄後,才能正常查看其他 API 請求。

這次也讓我學到,使用 DevTools 時不只要確認 Network 有沒有開啟,也要注意是否保留了之前的篩選條件。

6. 目前尚待最後確認的測試

這次已完成註冊資料庫確認、實際登入及重新整理後維持登入。

不過截至本文整理時,尚未取得登出後 /api/auth/me 回傳 401 的最終瀏覽器驗證紀錄。

因此,這部分仍列為待確認,不能直接寫成真實瀏覽器全部驗證完成。


十一、今日學習與 AI 協助

今日學習

這次開發與之前的醫師查詢 API 很不一樣。

Day 25 主要是讓 Angular 透過 GET 請求讀取 Oracle 資料,而 Day 26 開始需要處理會員新增、密碼安全及登入驗證。

Oracle Database

  • USERS 與 PATIENTS 資料表設計。
  • PRIMARY KEY、FOREIGN KEY、UNIQUE。
  • GENERATED ALWAYS AS IDENTITY。
  • CREATE TABLE 權限。
  • Transaction。
  • COMMIT 與 ROLLBACK。
  • Oracle RETURNING。

ASP.NET Core

  • AuthController。
  • Request/Response DTO。
  • PasswordHasher。
  • Cookie Authentication。
  • ClaimsPrincipal。
  • Authorization。
  • IAntiforgery。
  • Rate Limiting。
  • HTTP 400、401、403、409、429、503。

Angular

  • AuthService。
  • Reactive Forms。
  • 表單驗證。
  • HttpClient。
  • XSRF。
  • signals。
  • AuthState。
  • Route Guard。
  • Header 登入狀態。
  • 登入後 returnUrl。
  • Demo 與正式會員資料分離。

AI 協助

這次使用 Codex 協助檢查登入/註冊頁與原有 Demo SessionService、規劃 Oracle 資料表、建立 ASP.NET Core Auth API,以及串接 Angular AuthService。

但這次沒有直接讓 Codex 一次修改整個專案,而是依序進行:

檢查原有登入/註冊頁
          ↓
分析 Day 22 Oracle 設計
          ↓
準備 USERS/PATIENTS SQL
          ↓
SQL Developer 手動建表
          ↓
ASP.NET Core 註冊 API
          ↓
PasswordHasher、Cookie、CSRF
          ↓
後端測試
          ↓
Angular AuthService
          ↓
Reactive Forms 串接
          ↓
Header/Guard/Profile
          ↓
單元測試與瀏覽器驗證

每個階段完成後,再確認程式與測試結果,避免一次修改太多地方而難以追蹤問題。

其中 Oracle 建表、權限確認及註冊資料查詢,也透過 SQL Developer 實際操作。

這次最大的收穫,是逐漸理解「登入成功」不只是前端顯示成功訊息,而是包含帳號驗證、密碼雜湊、Cookie、CSRF、防止未授權存取,以及前後端狀態一致性。


十二、今日成果與下一步

今日完成

今天已將原本只有 Demo 功能的登入與註冊頁,逐步整合成由 ASP.NET Core 與 Oracle 支援的會員驗證功能。

主要完成:

  1. 確認 Angular 登入與註冊頁現有架構。
  2. 建立 Oracle USERS 資料表。
  3. 建立 Oracle PATIENTS 資料表。
  4. 使用 Identity 自動產生主鍵。
  5. 處理 ORA-01031 權限不足問題。
  6. 建立 ASP.NET Core 註冊 API。
  7. 使用 PasswordHasher 保存密碼雜湊。
  8. 透過 Oracle Transaction 建立會員與病人資料。
  9. 驗證註冊失敗時 Rollback。
  10. 建立登入、身分查詢及登出 API。
  11. 設定 Cookie Authentication。
  12. 加入 CSRF 防護。
  13. 加入登入及註冊 Rate Limiting。
  14. 建立 Angular AuthService。
  15. 完成登入與註冊 Reactive Forms 驗證。
  16. 將登入、註冊頁串接後端 API。
  17. 整合 Header 與 Route Guard。
  18. 分離正式會員資料與 Demo 預約資料。
  19. 完成 163/163 Angular 單元測試。
  20. 完成 TypeScript 檢查與 Production Build。
  21. 實際透過 Angular 註冊測試會員,並在 Oracle 查到帳號。
  22. 實際登入並確認會員資料。
  23. 確認重新整理後仍能保持登入狀態。

尚未完成

目前仍有以下項目需要後續處理:

  • 登出後 /me 回傳 401 的最終瀏覽器確認。
  • 正式預約掛號 API。
  • 我的預約資料與登入會員的正式串接。
  • 病人身分證與出生日期等資料的後續需求及安全設計。
  • 忘記密碼與帳號復原。
  • Email 或手機驗證。
  • 正式環境 HTTPS 與 Data Protection 金鑰部署。
  • 多伺服器環境的登入限流及登入憑證管理。

下一步規劃

Day 26 已完成本階段的登入與註冊 API 開發,接下來會先補齊最後的登出瀏覽器驗證,再繼續規劃智慧醫院預約網站的其他功能。

後續可以利用目前已建立的會員身分,進一步設計正式預約掛號流程。

不過在串接預約功能前,仍需要先確認日期化門診診次、預約名額,以及會員與預約紀錄之間的資料庫關聯。

這次最大的收穫,是從前一天單純讀取 Oracle 醫師資料,進一步學習如何將 Angular 表單、ASP.NET Core 身分驗證與 Oracle 交易整合起來。

也更清楚理解,真正的會員登入系統不只是驗證帳號密碼,還需要考慮資料一致性、安全性、錯誤處理、登入狀態及既有 Demo 功能的相容性。

這是 Day 26 最重要的開發成果。


上一篇
Day 25|Angular 串接醫師 API
下一篇
Day 27|預約掛號 API與 Oracle 整合測試
系列文
從 Figma 到 Angular:打造智慧醫院預約掛號系統的 30 天實作之旅 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言